#include "md5View.h"

cMd5Viewer g_Md5Viewer;

/*
==============
	md5Viewer
==============
*/

void cMd5Viewer::ReadMd5Mesh(Md5Mesh& md5mesh,string filename)
{
	ifstream fin(filename,fstream::in);
	if(fin.fail()){
		ERRBOX("Read Mesh File Failed\n");
	}
	string line;
	//discard the header
	getline(fin,line);
	getline(fin,line);

	string type;
	fin>>type>>md5mesh.numJoints;
	fin>>type>>md5mesh.numMeshes;

	md5mesh.vecJoint.clear();
	md5mesh.vecMesh.clear();

	md5mesh.vecJoint.resize(md5mesh.numJoints);
	md5mesh.vecMesh.resize(md5mesh.numMeshes);

	string discardChar;
	fin>>type>>discardChar;
	for(int i = 0;i!=md5mesh.numJoints;++i)
	{
		GetJoints(fin,md5mesh.vecJoint[i]);
	}
	fin>>discardChar;
	for(int i = 0;i!=md5mesh.numMeshes;++i)
	{
		GetMesh(fin,md5mesh.vecMesh[i]);
	}
	fin.close();
}

void cMd5Viewer::GetJoints(ifstream& fin,Joint& joint)
{
	string discardChar,parent;
	D3DXQUATERNION q;
	fin>>joint.bonename
		>>joint.parentIndex
		>>discardChar
		>>joint.pos.x>>joint.pos.y>>joint.pos.z
		>>discardChar
		>>discardChar
		>>joint.orient.x>>joint.orient.y>>joint.orient.z;

	fin.ignore(255,'\n');
	ComputeQuaternionW(joint.orient);
	QuatToMatrix(joint.orient,joint.matOrient);
}
void cMd5Viewer::GetMesh(ifstream& fin,Mesh& mesh)
{
	string type,discardChar,line;
	fin>>type>>discardChar;
	fin.ignore(1,'\n');
	getline(fin,line);
	fin>>discardChar>>mesh.shader;
	//
	mesh.shader = mesh.shader.substr( 1, mesh.shader.size() - 2 );

	fin>>type>>mesh.numVerts;
	mesh.vecVerts.clear();
	mesh.vecVerts.resize(mesh.numVerts);
	for(int i = 0;i!=mesh.numVerts;++i)
	{
		fin>>type>>discardChar
		   >>discardChar
		   >>mesh.vecVerts[i].texUV.x
		   >>mesh.vecVerts[i].texUV.y
		   >>discardChar
		   >>mesh.vecVerts[i].weightIndex
		   >>mesh.vecVerts[i].weightElem;
	}
	fin>>type>>mesh.numTris;
	mesh.vecTris.clear();
	mesh.vecTris.resize(mesh.numTris);
	for(int i = 0;i!=mesh.numTris;++i)
	{
		fin>>type>>discardChar
		   >>mesh.vecTris[i].vertIndex1
		   >>mesh.vecTris[i].vertIndex2
		   >>mesh.vecTris[i].vertIndex3;
	}
	fin>>type>>mesh.numWeights;
	mesh.vecWeights.clear();
	mesh.vecWeights.resize(mesh.numWeights);
	for(int i = 0;i!=mesh.numWeights;++i)
	{
		fin>>type>>discardChar
		   >>mesh.vecWeights[i].jointIndex
		   >>mesh.vecWeights[i].weightValue
		   >>discardChar
		   >>mesh.vecWeights[i].pos.x
		   >>mesh.vecWeights[i].pos.y
		   >>mesh.vecWeights[i].pos.z
		   >>discardChar;
	}
	fin>>discardChar;
	return;
}

void cMd5Viewer::ReadMd5Anim( Md5Anim& md5anim, string filename )
{
	string discardStr;
	ifstream fin( filename, ifstream::in );
	if( fin.fail() )
	{
		ERRBOX( "Read Anim File Failed \n" );
	}

	getline( fin, discardStr );
	getline( fin, discardStr );

	fin>>discardStr>>md5anim.numFrames
	   >>discardStr>>md5anim.numJoints
	   >>discardStr>>md5anim.frameRate
	   >>discardStr>>md5anim.numAnimatedComponents;

	md5anim.vecHierachy.clear();
	md5anim.vecBounds.clear();
	md5anim.vecBaseframe.clear();
	md5anim.vecFrame.clear();

	md5anim.vecHierachy.resize( md5anim.numJoints );
	md5anim.vecBounds.resize( md5anim.numFrames );
	md5anim.vecBaseframe.resize( md5anim.numJoints );
	md5anim.vecFrame.resize( md5anim.numFrames );
	for( int i = 0; i != md5anim.vecFrame.size(); ++i )
	{
		md5anim.vecFrame[ i ].vecAnimatedComp.resize( md5anim.numAnimatedComponents, 0.0f );
	}

	//read Hierachy
	fin>>discardStr>>discardStr;
	for( int i = 0; i != md5anim.numJoints; ++i)
	{
		GetHierachy( fin, md5anim.vecHierachy[ i ] );
	}
	fin>>discardStr;

	//read Bounds
	fin>>discardStr>>discardStr;
	for( int i = 0; i != md5anim.numFrames; ++i )
	{
		GetBound( fin, md5anim.vecBounds[ i ] );
	}
	fin>>discardStr;

	//read Baseframe
	fin>>discardStr>>discardStr;
	for( int i = 0; i != md5anim.numJoints; ++i )
	{
		GetBaseframe( fin, md5anim.vecBaseframe[ i ] );
	}
	fin>>discardStr;

	//read frames
	for( int i = 0;i != md5anim.numFrames; ++i )
	{
		fin>>discardStr>>md5anim.vecFrame[ i ].frameIndex>>discardStr;
		for( int j = 0; j != md5anim.numAnimatedComponents ; ++j )
		{
			fin>>md5anim.vecFrame[ i ].vecAnimatedComp[ j ];
		}
		fin>>discardStr;
	}
	md5anim.vecOffset.resize( md5anim.numFrames, 0.0f );
	return;
}

void cMd5Viewer::GetHierachy( ifstream& fin, Hierachy& hierachy )
{
	fin>>hierachy.jointName
	   >>hierachy.parentIndex
	   >>hierachy.numComp
	   >>hierachy.frameIndex;
	fin.ignore(255,'\n');
}

void cMd5Viewer::GetBound(  ifstream& fin, Bounds& bounds)
{
	string discardStr;
	fin>>discardStr
	   >>bounds.min.x>>bounds.min.y>>bounds.min.z
	   >>discardStr
	   >>discardStr
	   >>bounds.max.x>>bounds.max.y>>bounds.max.z
	   >>discardStr;
}

void cMd5Viewer::GetBaseframe( ifstream& fin,Baseframe& baseframe )
{
	string discardStr;
	fin>>discardStr
	   >>baseframe.pos.x>>baseframe.pos.y>>baseframe.pos.z
	   >>discardStr
	   >>discardStr
	   >>baseframe.orient.x>>baseframe.orient.y>>baseframe.orient.z
	   >>discardStr;

	ComputeQuaternionW( baseframe.orient );
	QuatToMatrix( baseframe.orient, baseframe.mat );
}

void cMd5Viewer::ReadMtr( Mtr& mtr, string filename )
{
	ifstream fin( filename, ifstream::in );

	if( fin.fail() )
	{
		ERRBOX( "Read MTR file failed\n" );
	}

	string getStr;
	while( fin>>getStr )
	{
		if( getStr == "table" ){
			fin.ignore( 255, '\n' );
		}
		else break;
	}

	string key;
	int leftBracket = 0;
	bool find = false;
	do {
		if( getStr == "//" )
		{
			fin.ignore( 255, '\n' );
			continue;
		}
		else if( getStr == "/*" ){
			while( fin>>getStr ){
				if( getStr == "*/" )
					break;
			}
			continue;
		}
		else if( getStr == "{" ){
			++leftBracket;
			continue;
		}
		else if( getStr == "}" ){
			--leftBracket;
			continue;
		}
		if( leftBracket == 0 ){
			key = getStr;
		}
		else if( leftBracket > 1 ){
			if( getStr == "blend" ){
				fin>>getStr;
				if( getStr == "diffusemap" ){
					fin>>getStr; //discard the next string
					find = true;
					continue;
				}
			}
		}
		else if( leftBracket == 1 ){
			if( getStr == "diffusemap" ){
				find = true;
				continue;
			}
		}
		if( find ){
			mtr.mapDiffuse.insert( make_pair( key, getStr ) );
			find = false;
		}
	}
	while ( fin>>getStr );
	return;
}

//////////////////////////////////////////////////////////////////////////
cMd5Viewer* GetMd5Viewer()
{
	return &g_Md5Viewer;
}
